﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BySoft.Web.Utility
{
    public sealed class RandomGenerator
    {
        private static string[] CharsArray = { "a", "c", "d", "e", "f", "h", "i", "j", "k", "n", "p", "r", "s", "t", "u", "v", "w", "x" };

        #region <GenerateRandomString>

        /*
		 * 目标：生成数字和字符混杂的4位字符串
		 * 步骤：
		 * 1.先从0-36中随机取出2个数字，这2个数中有几个小于25的数就从字符数组取几个字符
		 * (字符数cn<= 2)
		 * 2.从0-255中随机取出4-cn个数字，取每个数字的个位数
		 * 3.从0-3随机取出cn个数字，用来存放字符
		 * 4.数字倒序存放在剩下的位置
		 */

        //Use GetRandomNumber，Seed：17171717
        private static string[] GetRandomChar(int length)
        {
            int[] iRandom = new int[length];
            string[] letters = new string[length];
            iRandom = GetRandomNumber(length, 0, CharsArray.Length + 10, 17171717);
            for (int i = 0; i < length; i++)
            {
                if (iRandom[i] < CharsArray.Length)
                    letters[i] = CharsArray[iRandom[i]];
                else
                    letters[i] = "";
            }
            return letters;
        }


        /*
         * use the ticks of now to divide with seed and get the mod 
         * then use the mod as the first seed to get the first random number,
         * then use the first random number mutiply the first seed to get the second random number
         */
        private static int[] GetRandomNumber(int length, int minValue, int maxValue, int seed)
        {
            Random rnd = new Random(unchecked((int)DateTime.Now.Ticks % seed));
            int[] iResult = new int[length];
            int iFirst = rnd.Next(minValue, maxValue);
            for (int i = 0; i < length; i++)
            {
                iResult[i] = iFirst;
                rnd = new Random(unchecked((int)(iFirst * DateTime.Now.Ticks % seed)));
                iFirst = rnd.Next(minValue, maxValue);
            }
            return iResult;
        }


        //use the RNGCryptoServiceProvider class to get a random bytes array of assigned length
        private static byte[] GetRandByte(int length)
        {
            System.Security.Cryptography.RNGCryptoServiceProvider rndGenerator = new System.Security.Cryptography.RNGCryptoServiceProvider();
            byte[] btResult = new byte[length];
            rndGenerator.GetBytes(btResult);
            return btResult;
        }


        //Use GetRandomNumber，Seed：13131313,打乱顺序后随机抽取
        private static string GenerateRandomNumber(int numLength)
        {
            int length = 20;
            string[] strNums = new string[length];
            byte[] bArray = new byte[length];
            string sNum = "";

            //1.get a rand byte array
            bArray = GetRandByte(length);
            //2.Convert the byte-type number array to string array
            for (int i = 0; i < bArray.Length; i++)
            {
                strNums[i] = bArray[i].ToString();
                strNums[i] = strNums[i].PadLeft(2, '0');
            }

            //3.Get a serial random number between 0 and 99 with assigned length,
            //then change string array sequence by random number
            int[] ichange = new int[length];
            ichange = GetRandomNumber(length, 0, 99, 13131313);
            string tmp = "";
            int itmp;
            for (int ii = 0; ii < strNums.Length; ii++)
            {
                itmp = ichange[ii] % length;
                tmp = strNums[itmp];
                strNums[itmp] = strNums[length - 1 - itmp];
                strNums[length - 1 - itmp] = tmp;
            }

            //4.Get 2 random number between 0 and 99,
            //then use a temp variant "imid" to get the result of random-number mod with length,
            //use a temp string to join the two member of the string array
            //that is the very thing we want,It"s ok now !:)
            int[] iOut = new int[numLength];
            iOut = GetRandomNumber(numLength, 0, 99, 13131313);
            int imid;
            for (int jj = 0; jj < iOut.Length; jj++)
            {
                imid = iOut[jj] % length;
                sNum = strNums[imid].Substring(strNums[imid].Length - 1, 1) + sNum;
            }

            return sNum;
        }

        /// <summary>
        /// 用于生成随机只包含小写字符和阿拉伯数字的字符串。可以指定字符串长度，包含最多字符数
        /// </summary>
        /// <param name="length">字符串长度</param>
        /// <param name="maxNumerics">最多包含几个字符</param>
        /// <returns>生成的字符串</returns>
        public static string GetRandomString(int length, int maxAlphabetics)
        {
            if (length <= 0)
            {
                throw new Exception("随机数生成失败，无效的随机字符串长度");
            }

            if (length < maxAlphabetics)
            {
                throw new Exception("随机数生成失败，最多包含的字符数不能大于随机字符串的总长度");
            }

            string[] chars = GetRandomChar(maxAlphabetics);
            string nums = GenerateRandomNumber(length);
            string sChar = "";
            int ichars = 0;
            for (int i = 0; i < maxAlphabetics; i++)
            {
                if (chars[i] != "")
                {
                    sChar += chars[i];
                    ichars++;
                }
            }
            if (ichars > 0)
            {
                int[] iPoss = new int[ichars];
                iPoss = GetRandomNumber(ichars, 0, length - 1, 15151515);
                for (int j = 0; j < iPoss.Length; j++)
                {
                    nums = nums.Substring(0, iPoss[j])
                        + sChar.Substring(j, 1) + nums.Substring(iPoss[j] + 1, nums.Length - iPoss[j] - 1);
                }
            }
            return nums;
        }
        #endregion
    }
}
